XDL VideoView 활용 두 번째

NXVideoView를 활용하여 동영상 플레이어를 구현해 봅니다. 기본적인 동영상 플레이어 기능을 수행합니다.

들어가기 전에

설치 프로그램으로 배포되는 XDL 엔진은 Visual Studio 2022 x64 Release 버전으로, Visual Studio 2022 이상의 버전에서 사용 가능하다.
아래의 설명은 Visual Studio 2022를 기준으로 하겠다.

1 기본 프로그램 작성
1.1 Visual Studio 2022를 이용하여 예제 “XDL_VideoView1”의 “기본 프로그램 작성” 방법을 참고로 기본 프로젝트를 생성한다.

프로젝트 이름은 “XDL_VideoView2”로 한다

2 메뉴 생성하기
2.1 [도구상자]의 MenuStrip을 선택하고 Form1의 상단부에 끌어다가 배치한다..

2.2 메뉴에 다음과 같이 [File]-[Open]을 입력하여 생성한다.
3 Player 컨트롤 생성하기
3.1 동영상 플레이어를 위해 Play, Stop, Pause기능과 진행률을 표시하는 스크롤 기능을 구현하기 위해 다음과 같이 디자인을 수행한다.
먼저 TableLayoutPanel을 하부에 Docking시키고 3개의 Column으로 구성하여 버튼과 스크롤 및 label을 이용하여 다음과 같이 화면을 구성한다.
화면을 구성하는 방법은 C# 컨트롤에 대한 내용으로 여기서는 생략한다.

4 NXVideoView 컨트롤 추가하기
4.1 [도구상자]-[일반]에서 NXVideoView를 끓어다 Form1에 올려 놓는다.
NXVideoView컨트롤의 [부모컨테이너에서 도킹]버튼을 눌러 도킹한다.
또한 NXVideoOverlay컨트롤을 NXVideoView 컨트롤 위에 끌어다 올려놓는다.

4.2 NXVideoView를 [부모컨테이너에 도킹]을 눌러 전체화면으로 확장한다.

4.3 [F5]키를 눌러 프로그램을 실행한다. 아래와 같이 NXVideoView 컨트롤이 있는 프로그램이 실행된다.

4.4 프로그램을 종료한다.

5 동영상 열기 기능 구현
5.1 디자인창에서 Toolbar의 [File]-[Open]을 더블 클릭하여 함수를 자동 생성한다.

C#

                                    
private void toolStripMenuOpen_Click(object sender, EventArgs e)
{

}
                                    
                                

5.2 NXVideo객체들을 사용하기 위해서 다음과 같이 NXDL, NXVideo 네임스페이스를 추가한다.

C#

                                    
using Pixoneer.NXDL;
using Pixoneer.NXDL.NXVideo;

                                    
                                

5.3 NXVideoView구현시 필요한 XVideoIO, XVideo, XVideoChannel객체를 선언한다.

C#

                                    
enum VideoAction { STOP, PLAYING, PAUSED }

struct VideoState
{
    public XVideo video;                  // 파일이나 네트워크로부터 입력되는 스트리밍데이터를 제어하는 기능을 수행할 객체 선언
    public XVideoChannel videoChannel;    // 동영상 개체에 포함된 채널 객체 선언
    public string videoFilePath;          // 동영상 파일 경로 
    public VideoAction action;            // 비디오 플레이 상태를 정의하는 객체 선언
}

private XVideoIO m_videoIO = null;        // 동영상의 입출력을 담당할 객체 선언
private VideoState VS;                    // 비디오 상태를 관리하는 객체 선언


                                    
                                

5.4 Form1생성자에서 XVideoIO의 객체 생성 및 VideoState에 대한 초기화를 수행한다. 또한 프로그램 종료시에 메모리 관리 등을 위해 NXVideoView컨트롤의 초기화를 수행한다.

C#

                                    
enum public Form1()
{
    InitializeComponent();
    m_videoIO = new XVideoIO(); // VideoIO를 생성
    
    VideoInit();
    nxVideoLayerOverlay1.LayerVisible = true;
}

private void VideoInit()
{
    // VideoState의 초기화
    VS.video = null;   
    VS.videoChannel = null;    
    VS.videoFilePath = string.Empty;
    VS.action = VideoAction.STOP;
}
    
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    // 동영상 채널 정보 초기화
    nxVideoView1.ResetVideoChannel();

    if (VS.video != null)
    {
        // 동영상 객체 Close
        VS.video.Close();
        VS.video = null;
    }

    if (m_videoIO != null)
    {
        // 동영상 입출력 객체 Dispose
        m_videoIO.Dispose();
    }
}
                                    
                                

5.5 File-Open 버튼을 눌렀을 때 생성될 Open 대화상자와 선택된 파일에 대한 XVideo객체를 생성한다. 또한, XVideo객체에 실제 스트리밍을 담당하는 XVideoChannel객체를 활성화(Activate) 시켜 Frame을 내부적으로 생성하도록 지시한다.

C#

                                    
private void toolStripMenuOpen_Click(object sender, EventArgs e)
{
    // 새로운 파일 Open을 수행한다.
    OpenFileDialog openFileDialog = new OpenFileDialog();
    openFileDialog.Filter = "TS file(*.ts)|*.ts||";
    openFileDialog.RestoreDirectory = true;

    if (openFileDialog.ShowDialog() != DialogResult.OK) return;

    string videoPath = openFileDialog.FileName;

    // 동영상 파일의 존재 유무 체크
    if (System.IO.File.Exists(videoPath) == false)
    {
        MessageBox.Show(this, "해당 경로에 영상이 없습니다.", "오류");
        return;
    }

    // 파일 경로를 저장한다.
    VS.videoFilePath = videoPath;

    // 둥영상의 재생상태가 중지가 아닐 경우 동영상 재생 중지
    OnStop();

    // 동영상 스트리밍 환경을 생성한다.
    OnOpen();

    // 동영상을 Play한다.
    OnPlay();
}
                                    
                                

5.6 OnOpen함수에 동영상을 Play하기 위해 VS.videoFilePath에 설정된 파일 경로를 통해 NXVideoView컨트롤을 XVideoChannel로 초기화한다.

C#

                                    
// 동영상 파일 열기
public void OnOpen()
{
    try
    {
        string strError = null;
        // 동영상 스트림 정보 가져오기
        VS.video = m_videoIO.OpenFile(VS.videoFilePath, "XFFMPDRIVER", out strError);

        if (VS.video == null)
        {
            MessageBox.Show(this, "동영상 재생에 실패하였습니다. 파일을 확인해주십시오.", "파일 열기");
            return;
        }

        // 다중 채널을 가진 동영상 객체의 Channel 인덱스
        int nIdxChannel = 0;

        // 동영상 뷰에 재생할 동영상 채널을 성정
        nxVideoView1.SetVideoChannel(VS.video, nIdxChannel);

        // 입력 인덱스에 해당하는 Channel을 가져오기
        VS.videoChannel = VS.video.GetChannel(nIdxChannel);

        // GetChannel에 실패할 경우 Null 객체가 return되며, 그에 대한 예외처리
        if (VS.videoChannel == null)
        {
            MessageBox.Show(this, "동영상 재생에 실패하였습니다. 파일을 확인해주십시오.", "파일 열기");
            return;
        }

        // 동영상 객체에 포함된 Channel 객체 중 해당 Channel 객체를 활성화
        // 활성화된 객체만 스트리밍이 수행
        VS.videoChannel.Activate();

    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
        MessageBox.Show(this, "재생 실패!", "동영상");
        VS.action = VideoAction.STOP;
    }
}
                                    
                                

5.7 동영상을 재생하도록 지시하는 OnPlay, Play되고 있는 도중에 비디오를 멈추고 초기화하는 OnStop, Play되고 있는 도중에 Pause하는 OnPause함수를 구현한다.

C#

                                    
private void OnPlay()
{
    if (VS.action == VideoAction.PAUSED)  // 동영상이 중지 상태가 아닐경우
    {
         VS.videoChannel.Resume();        // 동영상 채널 Resume
         VS.action = VideoAction.PLAYING;
    }
    else  if (VS.action == VideoAction.STOP)                                // 동영상이 중지 상태일 경우
    {
        // 동영상 Channel을 처음부터 재생하다록 Play 신호 설정
        VS.videoChannel.Play();
        VS.action = VideoAction.PLAYING;
    }
}

// 동영상 멈춤버튼클릭 이벤트
private void OnPause()
{
    if (VS.action == VideoAction.PLAYING)
    {
        VS.videoChannel.Pause();         // 동영상 채널 Pause
        VS.action = VideoAction.PAUSED;
    }
}

// 동영상 정지버튼클릭 이벤트
public void OnStop()
{
    if (VS.videoChannel != null)
    {
        // 재생 Frame Buffer를 삭제
        VS.videoChannel.ClearFrameBuffer();
        // 동영상 재생 스크린을 갱신한다.
        nxVideoView1.RefreshScreen();
        // 동영상 재생 중지
        VS.videoChannel.Stop();
    }

    // 동영상 채널 정보 초기화
    nxVideoView1.ResetVideoChannel();

    if (VS.video != null)
    {
        // 동영상 객체 Close
        VS.video.Close();
        VS.video = null;
    }

    VS.action = VideoAction.STOP;
}
                                    
                                

5.8 Form1에 있는 을 눌렀을 때 수행되는 Event기능을 구현한다. 버튼의 [속성]창에서 클릭 이벤트를 생성한다.

C#

                                    
private void button_Play_Click(object sender, EventArgs e)
{
    // 비디오가 Stop인 상태인 경우 다시 비디오를 저장된 파일 경로로부터 Open해서 설정한다. 
    if (VS.action == VideoAction.STOP)
    {
        OnOpen();
    }

    // 설정된 비디오를 Play한다.
    OnPlay();
}

private void button_Pause_Click(object sender, EventArgs e)
{
    // Play되고 있는 비디오를 Pause한다.
    OnPause();
}

private void button_Stop_Click(object sender, EventArgs e)
{
    // Play되고 있는 비디오를 Stop한다.
    OnStop();
}
                                    
                                

5.9 [F5]키를 눌러 프로그램을 실행한다. [File]-[Open]메뉴를 눌러 stream.ts파일을 연다. 버튼을 눌러 기능을 확인한다.

1 기본 프로그램 작성
1.1 Visual Studio 2022를 이용하여 예제 “XDL_VideoView1”의 “기본 프로그램 작성” 방법을 참고로 기본 프로젝트를 생성한다.

프로젝트 이름은 “XDL_VideoView2”로 한다.

2 메뉴 생성하기
2.1 MainWindow.xaml창에서 기본으로 생성된 Grid 레이아웃에 Grid.RowDefinition을 이용하여 세 개의 Row을 생성한다. Menu를 첫 번째 Cell에 배치하고 MenuItem 항목을 추가하여 [File]과 [Open]을 생성한다. (자세한 메뉴 생성에 대한 설명은 XDL VideoView1 Tutorial을 참고한다.)

XAML

                                    
<Grid>
<Grid.RowDefinitions>
        <RowDefinition Height="30"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="40"/>
    </Grid.RowDefinitions>

    <Menu Grid.Row="0">
        <MenuItem Header="FIle" Margin="5,5,4,5">
            <MenuItem x:Name="openFileMenuItem" Header="_Open" Click="openFileMenuItem_Click"/>
        </MenuItem>
    </Menu>
</Grid>
                                    
                                

아래의 표를 참고하여 메뉴를 생성한다.

Control Type Header Name
MenuItem _File
MenuItem _Open openFileMenuItem

3 Player 컨트롤 생성하기
3.1 동영상 플레이어를 위해 “Play”, “Pause”, “Stop”기능과 진행률을 표시하는 스크롤 기능을 구현한다. 세 번째 Row의 Grid에 배치하고 이 Grid를 네 개의 Column으로 나누어 각각에 맞는 기능을 배치한다. 차례대로 (1) 에는 “Play” 버튼, (2) 에는 “Pause” 버튼, (3) “Stop” 버튼이 배치될 것이다.

샘플코드에서 이미지를 다운 받아 [속성] 창에 “브러시” 속성을 통해 알맞은 공간에 배치한다. 작업을 완료하면 아래와 같은 디자인을 얻을 수 있다. (자세한 설명은 샘플코드를 참고한다.)


4 NXVideoView 컨트롤 추가하기
4.1 Grid 레이아웃 내부에서 두 번째 Cell에 Grid를 배치하고 WindowsFormsHost 컨트롤을 도구상자로부터 끌어서 생성하거나 XAML 창에 입력하여 생성한다. 이는 Window forms를 Hosting 해주는 개체이며 Window Forms Control을 사용할 때 이용된다. (WindowFormIntegration와 System.Window.Forms을 어셈블리에 대한 참조 추가를 한다.)

4.2 앞서 추가한 namespace인 nxVideo를 이용하여 NXVideoView컨트롤을 불러온다. 이 NXVideoView의 이름(Name)은 nxVideoView1으로 한다. 또한 NXVideoOverlay컨트롤을 NXVideoView 컨트롤 위에 올려놓기 위해 불러오는 작업을 한다. XNVideoOverlay의 이름(Name)은 nxVideoLayerOverlay1이라고 한다.

XAML

                                    
<Grid Grid.Row="1">
    <WindowsFormsHost Grid.Column="0" Margin="3,0,3,3">
        <nxVideo:NXVideoView x:Name="nxVideoView1">
            <nxVideo:NXVideoView.Controls>
                <nxVideo:NXVideoLayerOverlay x:Name="nxVideoLayerOverlay1"/>
            </nxVideo:NXVideoView.Controls>
        </nxVideo:NXVideoView>
    </WindowsFormsHost>
</Grid>
                                    
                                

4.3 [F5] 키를 눌러 프로그램을 실행한다. 아래와 같이 NXVideoView 컨트롤이 있는 프로그램이 실행된다.

5 동영상 열기 기능 구현
5.1 Window창에서 Menu의 [File]-[Open]을 더블 클릭하여 함수를 자동 생성한다.

C#

                                    
private void openFileMenuItem_Click(object sender, RoutedEventArgs e)
{

}
                                    
                                

5.2 NXVideo객체들을 사용하기 위해서 다음과 같이 NXDL, NXVideo 네임스페이스를 추가한다.

C#

                                    
using Pixoneer.NXDL;
using Pixoneer.NXDL.NXVideo;
                                    
                                

5.3 NXVideoView구현시 필요한 XVideoIO, XVideo, XVideoChannel객체를 선언한다.

C#

                                    
public partial class MainWindow : Window
{
    enum VideoAction { STOP, PLAYING, PAUSED }
    struct VideoState
    {
        public XVideo video;                // 파일이나 네트워크로부터 입력되는 스트리밍데이터를 제어하는 기능을 수행할 객체 선언
        public XVideoChannel videoChannel;  // 동영상 개체에 포함된 채널 객체 선언
        public string videoFilePath;        // 동영상 파일 경로
        public VideoAction action;          // 비디오 플레이 상태를 정의하는 객체 선언
    }
    private XVideoIO m_videoIO = null;
    private VideoState VS;                  // 비디오 상태를 관리하는 객체 선언
                                    
                                

5.4 Window에 XVideoIO의 객체 생성 및 VideoState에 대한 초기화를 수행한다. 또한 프로그램 종료시, 메모리 관리 등을 위해 NXVideoView컨트롤의 초기화를 수행한다.

C#

                                    
public MainWindow()
{
    InitializeComponent();
    m_videoIO = new XVideoIO(); // VideoIO를 생성
    VideoInit();
    nxVideoLayerOverlay1.LayerVisible = true;
}

private void VideoInit()
{
    // VideoState의 초기화
    VS.video = null;
    VS.videoChannel = null;
    VS.videoFilePath = string.Empty;
    VS.action = VideoAction.STOP;
}

private void Window_Closing(object sender, CancelEventArgs e)
{
    // 동영상 채널 정보 초기화
    nxVideoView1.ResetVideoChannel();
    if (VS.video != null)
    {
        // 동영상 객체 Close
        VS.video.Close();
        VS.video = null;
    }
    if (m_videoIO != null)
    {
        // 동영상 입출력 객체 Dispose
        m_videoIO.Dispose();
    }
}
                                    
                                

5.5 [File]-[Open]을 눌렀을 때 생성될 Open 대화상자와 선택된 파일에 대한 XVideo객체를 생성한다. 또한, XVideo객체에 실제 스트리밍을 담당하는 XVideoChannel객체를 활성화(Activate) 시켜 Frame을 내부적으로 생성하도록 지시한다.

C#

                                    
private void openFileMenuItem_Click(object sender, RoutedEventArgs e)
{
    // 새로운 파일 Open을 수행한다.
    OpenFileDialog openFileDialog = new OpenFileDialog();
    openFileDialog.Filter = "TS file(*ts)|*.ts||";
    openFileDialog.RestoreDirectory = true;

    Nullable<bool> result = openFileDialog.ShowDialog();
    if (result != true) return;

    string videoPath = openFileDialog.FileName;
    // 동영상 파일의 존재 유무 체크
    if (System.IO.File.Exists(videoPath) == false)
    {
        MessageBox.Show(this, "해당 경로에 영상이 없습니다.", "오류");
        return; 
    }
            
    // 파일 경로를 저장한다.
    VS.videoFilePath = videoPath;
            
    // 동영상의 재생상태가 중지가 아닐 경우 동영상 재생 중지
    OnStop();
    // 동영상 스트리밍 환경을 생성한다.
    OnOpen();
    // 동영상을 Play한다.
    OnPlay();
}
                                    
                                

5.6 OnOpen함수에 동영상을 재생하기 위해서 VS.videoFilePath에 설정된 파일 경로를 통하여 NXVideoView컨트롤을 XVideoChannel로 초기화한다.

C#

                                    
// 동영상 파일 열기
public void OnOpen()
{
    try {
        string strError = null;
        // 동영상 스트림 정보 가져오기
        VS.video = m_videoIO.OpenFile(VS.videoFilePath, "XFFMPDRIVER", out strError);
        if (VS.video == null)
        {
            MessageBox.Show(this, "동영상 재생에 실패하였습니다. 파일을 확인해주세요.", "파일 열기");
            return;
        }

        // 다중 채널을 가진 동영상 객체의 Channel 인덱스
        int nIdxChannel = 0;
                
        // 동영상 뷰에 재생할 동영상 채널의 설정
        nxVideoView1.SetVideoChannel(VS.video, nIdxChannel);

        // 입력 인덱스에 해당하는 Channel 가져오기
        VS.videoChannel = VS.video.GetChannel(nIdxChannel);

        // GetChannel에 실패할 경우 Null 객체가 return되며, 그에 대한 예외처리
        if (VS.videoChannel == null)
        {
            MessageBox.Show(this, "동영상 재생에 실패하였습니다. 파일을 확인해주세요.", "파일 열기");
            return;
        }

        // 동영상 객체에 포함된 Channel 객체 중 해당 Channel 객체를 활성화
        // 활성화된 객체만 스트리밍이 수행
        VS.videoChannel.Activate();

    } catch (Exception e)
    {
        Console.WriteLine(e);
        MessageBox.Show(this, "재생 실패!", "동영상");
        VS.action = VideoAction.STOP;
    }
}
                                    
                                

5.7 동영상을 재생하도록 지시하는 OnPlay, Play되고 있는 도중에 비디오를 멈추고 초기화하는 OnStop, Play되고 있는 도중에 중지하는 OnPause함수를 구현한다.

C#

                                    
private void OnPlay()
{
    if (VS.action == VideoAction.PAUSED)    // 동영상이 중지 상태가 아닐경우
    {
        VS.videoChannel.Resume();           // 동영상 채널 Resume
        VS.action = VideoAction.PLAYING;
    } else if (VS.action == VideoAction.STOP)   // 동영상이 중지 상태일 경우
    {
        // 동영상 Channel을 처음부터 재생하도록 Play 신호 설정
        VS.videoChannel.Play();
        VS.action = VideoAction.PLAYING;
    }
}

private void OnPause()
{
    if (VS.action == VideoAction.PLAYING)
    {
        VS.videoChannel.Pause();    // 동영상 채널 Pause
        VS.action = VideoAction.PAUSED;
    }
}

private void OnStop()
{
    if (VS.videoChannel != null)
    {
        // 재생 Frame Buffer를 삭제
        VS.videoChannel.ClearFrameBuffer();
        // 동영상 재생 스크린을 갱신한다.
        nxVideoView1.RefreshScreen();
        // 동영상 재생 중지
        VS.videoChannel.Stop();
    }

    // 동영상 채널 정보 초기화
    nxVideoView1.ResetVideoChannel();

    if (VS.video != null)
    {
        // 동영상 객체 Close
        VS.video.Close();
        VS.video = null;
    }
    VS.action = VideoAction.STOP;
}
                                    
                                

5.8 Window 창에 있는 을 눌렀을 때 수행되는 기능을 구현한다. 버튼의 [속성]창에서 클릭 이벤트를 생성한다.

C#

                                    
private void playButton_Click(object sender, RoutedEventArgs e)
{
    // 비디오가 Stop 상태인 경우 다시 비디오를 저장된 파일 경로로부터 Open해서 설정한다.
    if (VS.action == VideoAction.STOP)
    {
        OnOpen();
    }
    // 설정된 비디오를 Play한다.
    OnPlay();
}

private void pauseButton_Click(object sender, RoutedEventArgs e)
{
    // Play되고 있는 비디오를 Pause한다.
    OnPause();
}

private void stopButton_Click(object sender, RoutedEventArgs e)
{
    // Play되고 있는 비디오를 Stop한다.
    OnStop();
}
                                    
                                

5.9 [F5] 키를 눌러 프로그램을 실행한다. [File]-[Open] 메뉴를 눌러 stream.ts파일을 연다. 버튼을 눌러 기능을 확인한다